/*
  mapping the IDIA's interface related stuffs to string and vice versa

  mainly transfer value(char int ...), bool, enum, string, VARIANT to string.
  
  $Id$
*/

#pragma once

#include "dia2.h"
#include "diacreate.h"
//#include "cvconst.h"

#include <utility>
#include <map>
#include <string>
#include "dia2.h"

//#import "msdia80.dll" //compile error for msdia80.tlh
#include <comip.h>	// _com_ptr_t

#include "miscutil.h"
#include "smpio.h"

//_COM_SMARTPTR_TYPEDEF(IDiaSymbol, __uuidof(IDiaSymbol));
//
// !!!_COM_SMARTPTR_TYPEDEF compile error!!!
// use follows!
typedef _com_ptr_t<_com_IIID<IDiaSymbol, &__uuidof(IDiaSymbol)> > IDiaSymbolPtr;
typedef _com_ptr_t<_com_IIID<IDiaEnumSymbols, &__uuidof(IDiaEnumSymbols)> > IDiaEnumSymbolsPtr;

using namespace std;

class CIDIASymb2Str
{
friend class CInit_CIDIASymb2Str;

//
// must construct with IDiaSymbol
public:
	CIDIASymb2Str(IDiaSymbol* pSymbol):m_pSymbol(pSymbol){};
	~CIDIASymb2Str(void){};
protected:
	CIDIASymb2Str(void);

//
// some static functions
public:
	// return SymTagEnum's name
	static const _tstring GetSymTagName(enum SymTagEnum symtag){return mapSymTagEnum[symtag];};
	// the supported property's number
	static DWORD GetPropertyNum();
	// return the property name's array.
	static const _tstring* GetPropertyS(){return &m_vcSProperty[0];};

//
// use the function name call function. 
// for example: PropertyVal(symIndexId) will call symIndexId()
public:
	_tstring PropertyVal(const _tstring *pcProp){return (this->*m_mapPropName2Fun[*pcProp])();};

//
// the stringfied functions of IDia interface.
public:
typedef _tstring (CIDIASymb2Str::*DIASymb_mf)(void);
	_tstring symIndexId(){ return GetVal<DWORD>(&IDiaSymbol::get_symIndexId);};
	_tstring symTag(){return GetEnumName(&IDiaSymbol::get_symTag, &mapSymTagEnum);};
	_tstring name(){ return GetBSTR(&IDiaSymbol::get_name);};
//	_tstring lexicalParent();
//	_tstring classParent();
//	_tstring type();	//Returns the IDiaSymbol interface that represents the function signature
	_tstring dataKind(){return GetEnumName(&IDiaSymbol::get_dataKind, &mapDataKind);};
	_tstring locationType(){return GetEnumName(&IDiaSymbol::get_locationType, &mapLocationType);};
	_tstring addressSection(){ return GetVal<DWORD>(&IDiaSymbol::get_addressSection,16);};
	_tstring addressOffset(){ return GetVal<DWORD>(&IDiaSymbol::get_addressOffset,16);};
	_tstring relativeVirtualAddress(){ return GetVal<DWORD>(&IDiaSymbol::get_relativeVirtualAddress,16);};
	_tstring virtualAddress(){ return GetVal<ULONGLONG>(&IDiaSymbol::get_virtualAddress,16);};
	_tstring registerId(){ return GetVal<DWORD>(&IDiaSymbol::get_registerId,16);};
	_tstring offset(){ return GetVal<LONG>(&IDiaSymbol::get_offset,16);};
	_tstring length(){ return GetVal<ULONGLONG>(&IDiaSymbol::get_length,16);};
	_tstring slot(){ return GetVal<DWORD>(&IDiaSymbol::get_slot,16);};
	_tstring volatileType(){ return GetBOOL(&IDiaSymbol::get_volatileType);};
	_tstring constType(){ return GetBOOL(&IDiaSymbol::get_constType);};
	_tstring unalignedType(){ return GetBOOL(&IDiaSymbol::get_unalignedType);};
	_tstring access(){return GetEnumName(&IDiaSymbol::get_access, &mapCV_access_e);};
	_tstring libraryName(){ return GetBSTR(&IDiaSymbol::get_libraryName);};
	_tstring platform(){return GetEnumName(&IDiaSymbol::get_platform, &mapCV_CPU_TYPE_e);};
	_tstring language(){return GetEnumName(&IDiaSymbol::get_language, &mapCV_CFL_LANG);};
	_tstring editAndContinueEnabled(){ return GetBOOL(&IDiaSymbol::get_editAndContinueEnabled);};
	_tstring frontEndMajor(){ return GetVal<DWORD>(&IDiaSymbol::get_frontEndMajor);};
	_tstring frontEndMinor(){ return GetVal<DWORD>(&IDiaSymbol::get_frontEndMinor);};
	_tstring frontEndBuild(){ return GetVal<DWORD>(&IDiaSymbol::get_frontEndBuild);};
	_tstring backEndMajor(){ return GetVal<DWORD>(&IDiaSymbol::get_backEndMajor);};
	_tstring backEndMinor(){ return GetVal<DWORD>(&IDiaSymbol::get_backEndMinor);};
	_tstring backEndBuild(){ return GetVal<DWORD>(&IDiaSymbol::get_backEndBuild);};
	_tstring sourceFileName(){ return GetBSTR(&IDiaSymbol::get_sourceFileName);};
//1 !there is no objectFilename as msdn said
//	_tstring objectFilename(){ return GetBSTR(&IDiaSymbol::get_objectFilename);};
	_tstring thunkOrdinal(){ return GetVal<DWORD>(&IDiaSymbol::get_thunkOrdinal);};
	_tstring thisAdjust(){ return GetVal<LONG>(&IDiaSymbol::get_thisAdjust);};
	_tstring virtualBaseOffset(){ return GetVal<DWORD>(&IDiaSymbol::get_virtualBaseOffset,16);};
	_tstring get_virtual(){ return GetBOOL(&IDiaSymbol::get_virtual);};
	_tstring intro(){ return GetBOOL(&IDiaSymbol::get_intro);};
	_tstring pure(){ return GetBOOL(&IDiaSymbol::get_pure);};
	_tstring callingConvention(){return GetEnumName(&IDiaSymbol::get_callingConvention, &mapCV_call_e);};
	_tstring value(){ return GetVARIANT(&IDiaSymbol::get_value);};
	_tstring baseType(){return GetEnumName(&IDiaSymbol::get_baseType, &mapBasicType);};
	_tstring token(){ return GetVal<DWORD>(&IDiaSymbol::get_token);};
	_tstring timeStamp(){ return GetVal<DWORD>(&IDiaSymbol::get_timeStamp);};
//	_tstring guid();
	_tstring symbolsFileName(){ return GetBSTR(&IDiaSymbol::get_symbolsFileName);};
	_tstring reference(){ return GetBOOL(&IDiaSymbol::get_reference);};
	_tstring count(){ return GetVal<DWORD>(&IDiaSymbol::get_count);};
	_tstring bitPosition(){ return GetVal<DWORD>(&IDiaSymbol::get_bitPosition);};
//	_tstring arrayIndexType();
	_tstring packed(){ return GetBOOL(&IDiaSymbol::get_packed);};
	_tstring constructor(){ return GetBOOL(&IDiaSymbol::get_constructor);};
	_tstring overloadedOperator(){ return GetBOOL(&IDiaSymbol::get_overloadedOperator);};
	_tstring nested(){ return GetBOOL(&IDiaSymbol::get_nested);};
	_tstring hasNestedTypes(){ return GetBOOL(&IDiaSymbol::get_hasNestedTypes);};
	_tstring hasAssignmentOperator(){ return GetBOOL(&IDiaSymbol::get_hasAssignmentOperator);};
	_tstring hasCastOperator(){ return GetBOOL(&IDiaSymbol::get_hasCastOperator);};
	_tstring scoped(){ return GetBOOL(&IDiaSymbol::get_scoped);};
	_tstring virtualBaseClass(){ return GetBOOL(&IDiaSymbol::get_virtualBaseClass);};
	_tstring indirectVirtualBaseClass(){ return GetBOOL(&IDiaSymbol::get_indirectVirtualBaseClass);};
	_tstring virtualBasePointerOffset(){ return GetVal<LONG>(&IDiaSymbol::get_virtualBasePointerOffset, 16);};
//	_tstring virtualTableShape();
	_tstring lexicalParentId(){ return GetVal<DWORD>(&IDiaSymbol::get_lexicalParentId);};
	_tstring classParentId(){ return GetVal<DWORD>(&IDiaSymbol::get_classParentId);};
	_tstring typeId(){ return GetVal<DWORD>(&IDiaSymbol::get_typeId);};
	_tstring arrayIndexTypeId(){ return GetVal<DWORD>(&IDiaSymbol::get_arrayIndexTypeId);};
	_tstring virtualTableShapeId(){ return GetVal<DWORD>(&IDiaSymbol::get_virtualTableShapeId);};
	_tstring code(){ return GetBOOL(&IDiaSymbol::get_code);};
	_tstring function(){ return GetBOOL(&IDiaSymbol::get_function);};
	_tstring managed(){ return GetBOOL(&IDiaSymbol::get_managed);};
	_tstring msil(){ return GetBOOL(&IDiaSymbol::get_msil);};
	_tstring virtualBaseDispIndex(){ return GetVal<DWORD>(&IDiaSymbol::get_virtualBaseDispIndex);};
	_tstring undecoratedName(){ return GetBSTR(&IDiaSymbol::get_undecoratedName);};
	_tstring age(){ return GetVal<DWORD>(&IDiaSymbol::get_age);};
	_tstring signature(){ return GetVal<DWORD>(&IDiaSymbol::get_signature);};
	_tstring compilerGenerated(){ return GetBOOL(&IDiaSymbol::get_compilerGenerated);};
	_tstring addressTaken(){ return GetBOOL(&IDiaSymbol::get_addressTaken);};
	_tstring rank(){ return GetVal<DWORD>(&IDiaSymbol::get_rank);};
//	_tstring lowerBound();
//	_tstring upperBound();
	_tstring lowerBoundId(){ return GetVal<DWORD>(&IDiaSymbol::get_lowerBoundId);};
	_tstring upperBoundId(){ return GetVal<DWORD>(&IDiaSymbol::get_upperBoundId);};
//	_tstring dataBytes();
	_tstring targetSection(){ return GetVal<DWORD>(&IDiaSymbol::get_targetSection,16);};
	_tstring targetOffset(){ return GetVal<DWORD>(&IDiaSymbol::get_targetOffset,16);};
	_tstring targetRelativeVirtualAddress(){ return GetVal<DWORD>(&IDiaSymbol::get_targetRelativeVirtualAddress,16);};
	_tstring targetVirtualAddress(){ return GetVal<ULONGLONG>(&IDiaSymbol::get_targetVirtualAddress,16);};
	_tstring machineType(){ return GetEnumName(&IDiaSymbol::get_machineType,&mapCV_CPU_TYPE_e);};	// it seems that get_machineType return a invalid value:0x14c
	_tstring oemId(){ return GetVal<DWORD>(&IDiaSymbol::get_oemId,16);};
	_tstring oemSymbolId(){ return GetVal<DWORD>(&IDiaSymbol::get_oemSymbolId);};
//	_tstring types();
//	_tstring typeIds();
//	_tstring objectPointerType();
	_tstring udtKind(){ return GetEnumName(&IDiaSymbol::get_udtKind,&mapUdtKind);};;

//
// basic functions's abstract 
private:
	template<class T> _tstring GetVal(HRESULT (STDMETHODCALLTYPE IDiaSymbol::*mpf)(T*), int radix=10);
//	_tstring GetVal<DWORD>(HRESULT (STDMETHODCALLTYPE IDiaSymbol::*mpf)(DWORD*), int radix=10);
	_tstring GetBOOL(HRESULT (STDMETHODCALLTYPE IDiaSymbol::*mpf)(BOOL*));
	_tstring GetBSTR(HRESULT (STDMETHODCALLTYPE IDiaSymbol::*mpf)(BSTR*));
	_tstring GetEnumName(HRESULT (STDMETHODCALLTYPE IDiaSymbol::*mpf)(DWORD*), map<DWORD,_tstring>* pMap);
	_tstring GetVARIANT(HRESULT (STDMETHODCALLTYPE IDiaSymbol::*mpf)(VARIANT*));

//
//
private:
	IDiaSymbolPtr m_pSymbol;

//
// the map propertys to string
//private:
public:	// change to public for others can use this maps
	static map<DWORD,_tstring> mapBasicType;
	static map<DWORD,_tstring> mapCV_access_e;
	static map<DWORD,_tstring> mapCV_call_e;
	static map<DWORD,_tstring> mapCV_CFL_LANG;
	static map<DWORD,_tstring> mapCV_CPU_TYPE_e;
	static map<DWORD,_tstring> mapCV_HREG_e;
	static map<DWORD,_tstring> mapDataKind;
	static map<DWORD,_tstring> mapLocationType;
	static map<DWORD,_tstring> mapNameSearchOptions;
	static map<DWORD,_tstring> mapSymTagEnum;
	static map<DWORD,_tstring> mapTHUNK_ORDINAL;
	static map<DWORD,_tstring> mapUdtKind;

//
// map string to function
private:
	// IDIA interace functions' name
	static _tstring m_vcSProperty[];	// null terminate for init
	static DIASymb_mf m_pmfS[];		// null terminate for init
	static map<_tstring, DIASymb_mf> m_mapPropName2Fun;
};

//
// for the map init is complex, so use another class to init the CIDIASymb2Str
// 
class CInit_CIDIASymb2Str
{
public:
	CInit_CIDIASymb2Str();

private:
// the map to be inited
	static map<DWORD,_tstring> *pMap[];
// the pairs for init map
	static pair<DWORD,_tstring>* pPairs[];

//
// the map propertys to string
private:
	static pair<DWORD,_tstring> pairBasicType[];
	static pair<DWORD,_tstring> pairCV_access_e[];
	static pair<DWORD,_tstring> pairCV_call_e[];
	static pair<DWORD,_tstring> pairCV_CFL_LANG[];
	static pair<DWORD,_tstring> pairCV_CPU_TYPE_e[];
	static pair<DWORD,_tstring> pairCV_HREG_e[];
	static pair<DWORD,_tstring> pairDataKind[];
	static pair<DWORD,_tstring> pairLocationType[];
	static pair<DWORD,_tstring> pairNameSearchOptions[];
	static pair<DWORD,_tstring> pairSymTagEnum[];
	static pair<DWORD,_tstring> pairTHUNK_ORDINAL[];
	static pair<DWORD,_tstring> pairUdtKind[];
};


template<class T> 
_tstring CIDIASymb2Str::GetVal(HRESULT (STDMETHODCALLTYPE IDiaSymbol::*mpf)(T*), int radix)
{
	T t;
	_tstringstream ss; 
	if(SUCCEEDED((m_pSymbol->*mpf)(&t)))
	{
		if(10==radix)
		{
			ss<<t;
		}
		else
		{
			ss<<_T("0x")<<hex<<t;
		}
	}
	return ss.str();
}

